package com.zksite.nator.client.server.handler;

import javax.annotation.Resource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import com.zksite.nator.common.constants.Constants;
import com.zksite.nator.common.exception.PingTimeoutException;
import com.zksite.nator.common.processor.RequestProcessor;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;

@Component
@Scope("prototype")
public class NatorClientHandler extends ChannelInboundHandlerAdapter {

	private static final Logger LOGGER = LoggerFactory.getLogger(NatorClientHandler.class);

	@Resource(name = "defaultForwardRequestProcessor")
	private RequestProcessor forwardProcessor;

	@Resource(name = "internalRequestProcessor")
	private RequestProcessor internalRequestProcessor;

	@Override
	public void channelActive(ChannelHandlerContext ctx) throws Exception {
	}

	public NatorClientHandler() {
	}

	@Override
	public void channelRead(final ChannelHandlerContext ctx, final Object msg) throws Exception {
		if (msg instanceof HttpRequest) {
			HttpRequest request = (HttpRequest) msg;
			HttpHeaders headers = request.headers();
			String mtyp = headers.get(Constants.MESSAGE_TYPE);
			if (mtyp != null) {// 如果带有自带头部，内部处理器处理请求
				internalRequestProcessor.process(ctx, msg);
			} else {
				forwardProcessor.process(ctx, request);
			}
		}
	}

	@Override
	public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
		if (evt instanceof IdleStateEvent) {
			IdleState state = ((IdleStateEvent) evt).state();
			if (state == IdleState.READER_IDLE) {// 5秒没有收到服务端的ping信息，链接断开
				LOGGER.error("time out receive ping message");
				throw new PingTimeoutException("idle exception");
			}
		} else {
			super.userEventTriggered(ctx, evt);
		}
	}

	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
		if (cause instanceof PingTimeoutException) {
			ctx.close();
		}
	}

}
